namespace Radar.Test
{
    using System;
    using Moq;
    using NUnit.Framework;

    [TestFixture]
    public class FactoryBuilderTest
    {
        private abstract class AbstractClass { }

        private interface IInterface { }

        private class X : FactoryBuilder
        {
            public X(Type implementationType, IContainer container, IConfigurationProvider configurationProvider)
                : base(implementationType, container, configurationProvider)
            {
            }

            protected override Type FindSuitableType(Type baseType, params Type[] arguments)
            {
                return baseType;
            }
        }

        private IFactoryBuilder builder;
        private IConfigurationProvider configurationProvider;
        private Mock<IContainer> container;

        [SetUp]
        public void SetUp()
        {
            container = new Mock<IContainer>();
            configurationProvider = new IocConfiguration(container.Object);

            builder = new X(typeof(object), container.Object, configurationProvider);
        }

        [Test]
        public void WillUseLifetime()
        {
            ((IIocConfiguration)configurationProvider).WithLifetime(Lifetime.Singleton);

            var f = builder.GetFactoryMethod();

            var x1 = f(new ResolveContext());
            var x2 = f(new ResolveContext());

            Assert.That(x1, Is.EqualTo(x2));
        }

        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void WillThrowOnNullTypeInConstructor()
        {
            new X(null, container.Object, configurationProvider);
        }

        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void WillThrowOnNullContainerInConstructor()
        {
            new X(typeof(object), null, configurationProvider);
        }

        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void WillThrowOnNullConfigurationInConstructor()
        {
            new X(typeof(object), container.Object, null);
        }

        [Test, ExpectedException(typeof(IocConfigurationException))]
        public void WillThrowOnAbstractType()
        {
            new X(typeof(AbstractClass), container.Object, configurationProvider);
        }

        [Test, ExpectedException(typeof(IocConfigurationException))]
        public void WillThrowOnInterface()
        {
            new X(typeof(IInterface), container.Object, configurationProvider);
        }
    }
}